`ifndef EX_V
`define EX_V


`include "defines.v"

module ex(
    // from id_ex
    input  wire[`InstAddrWidth - 1 : 0] inst_addr_i     ,   // 指令地址传递
    input  wire[`InstWidth - 1 : 0]     inst_i          ,   // 指令传递
    input  wire[`RegAddrWidth - 1 : 0]  reg_waddr_i     ,   // 回写地址
    input  wire                         reg_wen_i       ,   // 回写使能
    input  wire[`RegDataWidth - 1 : 0]  reg1_rdata_i    ,   // 寄存器 1 值传递
    input  wire[`RegDataWidth - 1 : 0]  reg2_rdata_i    ,   // 寄存器 2 值传递
    input  wire[`OPWidth - 1 : 0]       op1_i           ,   // 操作数 1
    input  wire[`OPWidth - 1 : 0]       op2_i           ,   // 操作数 2

    // to regs
    // from ex
    output reg[`RegAddrWidth - 1 : 0]   waddr_o,
    output reg[`RegDataWidth - 1 : 0]   wdata_o,
    output reg                          wen_o
);

wire[6:0] opcode;
wire[2:0] funct3;
wire[6:0] funct7;
wire[4:0] rd    ;
wire[4:0] rs1   ;
wire[4:0] rs2   ;

assign opcode = inst_i[6:0];
assign funct3 = inst_i[14:12];
assign funct7 = inst_i[31:25];
assign rd     = inst_i[11:7];
assign rs1    = inst_i[19:15];
assign rs2    = inst_i[24:20];

always @(*) begin
    case(opcode)
        `INST_TYPE_I : begin
            case(funct3)
                `INST_ADDI : begin
                    waddr_o = reg_waddr_i;
                    wdata_o = op1_i + op2_i;
                    wen_o = 1'b1;
                end

                default : begin
                    waddr_o = `R_X0_ADDR;
                    wdata_o = `R_X0_DATA;
                    wen_o = 1'b0;
                end
            endcase // case(funct3)
        end

         `INST_TYPE_R : begin
            case(funct3)
                `INST_ADD_SUB : begin
                    waddr_o = reg_waddr_i;
                    wen_o = 1'b1;
                    if(inst_i[30] == 1'b1) begin
                        wdata_o = op1_i - op2_i;
                    end
                    else begin
                        wdata_o = op1_i + op2_i;
                    end
                end

                default : begin
                    waddr_o = `R_X0_ADDR;
                    wdata_o = `R_X0_DATA;
                    wen_o = 1'b0;
                end
            endcase // case(funct3)
        end

        default : begin
            waddr_o = `R_X0_ADDR;
            wdata_o = `R_X0_DATA;
            wen_o = 1'b0;
        end
    endcase 
end

endmodule


`endif // EX_V